#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
#include "LogMessage.hpp"

template <class T>
class RingQueue
{
public:
    RingQueue(size_t size = 5)
        : _size(5), _ringqueue(_size), _pos_productor(0), _pos_consumer(0)
    {
        sem_init(&_sem_productor, 0, _size);
        sem_init(&_sem_consumer, 0, 0);
        pthread_mutex_init(&_mutex_productor, nullptr);
        pthread_mutex_init(&_mutex_consumer, nullptr);
    }

    void Push(T &in)
    {
        // 申请信号量成功
        P(_sem_productor);

        // 放数据(多进程需要加锁，防止多个执行流同时访问临界资源)
        pthread_mutex_lock(&_mutex_productor);
        _ringqueue[_pos_productor] = in;
        _pos_productor++;
        _pos_productor %= _size;
        pthread_mutex_unlock(&_mutex_productor);

        // 通知消费者取数据
        V(_sem_consumer);
    }

    void Pop(T *out)
    {
        // 申请信号量成功
        P(_sem_consumer);

        // 拿数据(多进程需要加锁，防止多个执行流同时访问临界资源)
        pthread_mutex_lock(&_mutex_consumer);
        *out = _ringqueue[_pos_consumer];
        _pos_consumer++;
        _pos_consumer %= _size;
        pthread_mutex_unlock(&_mutex_consumer);


        // 通知生产者生产数据
        V(_sem_productor);
    }

    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t& sem)
    {
        sem_post(&sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_sem_productor);
        sem_destroy(&_sem_consumer);
        pthread_mutex_destroy(&_mutex_productor);
        pthread_mutex_destroy(&_mutex_consumer);
    }

private:
    size_t _size;
    std::vector<T> _ringqueue;

    sem_t _sem_productor;
    sem_t _sem_consumer;
    pthread_mutex_t _mutex_productor;
    pthread_mutex_t _mutex_consumer;

    size_t _pos_productor;
    size_t _pos_consumer;
};